/*
 * CHttpClient.cpp
 *
 *  Created on: 2017年3月31日
 *      Author: chuanjiang.zh
 */

#include "CHttpClient.h"

static void ev_handler(struct mg_connection *nc, int ev, void *ev_data)
{
	CHttpClient* client = (CHttpClient*)(nc->mgr->user_data);
	client->handleEvent(nc, ev, ev_data);
}

CHttpClient::CHttpClient():
		m_connection(),
		m_recvBytes(),
		m_callback()
{
	mg_mgr_init(&mgr, NULL);

	mgr.user_data = this;
}

CHttpClient::~CHttpClient()
{
	close();

	mg_mgr_free(&mgr);
}

bool CHttpClient::get(const std::string& url, const StringMap& headers, HttpClientCallback* callback)
{
	return request(url, "GET", headers, std::string(), callback);
}

bool CHttpClient::post(const std::string& url, const StringMap& headers, const std::string& body, HttpClientCallback* callback)
{
	return request(url, "POST", headers, body, callback);
}

bool CHttpClient::request(const std::string& url, const std::string& httpMethod, const StringMap& headers, const std::string& body,
	HttpClientCallback* callback)
{
	m_callback = callback;

	std::string extra_headers;
	for (StringMap::const_iterator it = headers.begin(); it != headers.end(); ++ it)
	{
		extra_headers += it->first;
		extra_headers += ":";
		extra_headers += it->second;
		extra_headers += "\r\n";
	}

	m_connection = mg_connect_http(&mgr, ev_handler, url.c_str(), extra_headers.c_str(), body.c_str());

	start();

	return m_connection != NULL;
}

bool CHttpClient::upload(const std::string& url, const StringMap& headers, const std::string& body, HttpClientCallback* callback)
{
	m_callback = callback;

	std::string extra_headers;
	for (StringMap::const_iterator it = headers.begin(); it != headers.end(); ++it)
	{
		extra_headers += it->first;
		extra_headers += ":";
		extra_headers += it->second;
		extra_headers += "\r\n";
	}

	m_connection = mg_connect_http2(&mgr, ev_handler, url.c_str(), 
		extra_headers.c_str(), body.c_str(), body.size());

	start();

	return m_connection != NULL;
}

void CHttpClient::close()
{
	if (isRunning())
	{
		stop();
	}
}

bool CHttpClient::isOpen()
{
	return m_connection != NULL;
}

int CHttpClient::run()
{
	while (!m_canExit)
	{
		mg_mgr_poll(&mgr, 1000);
	}
	return 0;
}

void CHttpClient::handleEvent(struct mg_connection *nc, int ev, void *ev_data)
{
	struct http_message *hm = (struct http_message *) ev_data;
	//printf("CHttpClient::handleEvent. ev:%d\n", ev);

	switch (ev)
	{
		case MG_EV_CONNECT:
		{
			int code = *((int *)ev_data);
			if (code != 0)
			{
				const char* text = strerror(code);
				fireCallback(code, text, strlen(text));
			}
			break;
		}
		case MG_EV_RECV:
		{
			int num_bytes = *((int*)ev_data);
			m_recvBytes += num_bytes;
			//printf("recv. total:%d, len:%d\n", m_recvBytes, num_bytes);
			break;
		}
		case MG_EV_HTTP_REPLY:
		{
			nc->flags |= MG_F_CLOSE_IMMEDIATELY;
			fireCallback(hm->resp_code, hm->body.p, hm->body.len);
			break;
		}
		default:
		{
			break;
		}
	}
}

void CHttpClient::fireCallback(int code, const char* data, size_t length)
{
	//printf("CHttpClient::fireCallback\n");

	if (m_callback)
	{
		m_callback->handleResponse(code, data, length);
	}

	m_canExit = true;
}
